package cn.coufran.springboot.starter.http;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MultipartBody {
    private final List<MultipartBodyEntry> entries = new ArrayList<>();

    List<MultipartBodyEntry> getEntries() {
        return Collections.unmodifiableList(entries);
    }

    class MultipartBodyEntry {
        private final String name;
        private final InputStream inputStream;
        private final boolean isFile;
        private final String fileName;
        private final MediaType mediaType;

        MultipartBodyEntry(String name, InputStream inputStream, boolean isFile, String fileName, MediaType mediaType) {
            this.name = name;
            this.inputStream = inputStream;
            this.isFile = isFile;
            this.fileName = fileName;
            this.mediaType = mediaType;
        }

        MultipartBodyEntry(String name, InputStream inputStream) {
            this(name, inputStream, false, null, null);
        }

        MultipartBodyEntry(String name, InputStream inputStream, String fileName) {
            this(name, inputStream, true, fileName, null);
        }

        MultipartBodyEntry(String name, InputStream inputStream, String fileName, MediaType mediaType) {
            this(name, inputStream, true, fileName, mediaType);
        }

        String getName() {
            return name;
        }

        InputStream getInputStream() {
            return inputStream;
        }

        boolean isFile() {
            return isFile;
        }

        String getFileName() {
            return fileName;
        }

        MediaType getMediaType() {
            return mediaType;
        }
    }

    public class Builder {
        public Builder addPart(String name, InputStream inputStream) {
            entries.add(new MultipartBodyEntry(name, inputStream));
            return this;
        }

        public Builder addPart(String name, InputStream inputStream, String fileName) {
            entries.add(new MultipartBodyEntry(name, inputStream, fileName));
            return this;
        }

        public Builder addPart(String name, InputStream inputStream, String fileName, MediaType mediaType) {
            entries.add(new MultipartBodyEntry(name, inputStream, fileName, mediaType));
            return this;
        }

        public Builder addPart(String name, Path path) throws IOException {
            File file = path.toFile();
            if (!file.exists()) {
                throw new FileNotFoundException("File not found: " + path);
            }
            if (!file.isFile()) {
                throw new FileNotFoundException("Not a file: " + path);
            }
            String fileName = file.getName();
            String mediaTypeStr = Files.probeContentType(path);
            MediaType mediaType = null;
            if (mediaTypeStr != null) {
                mediaType = MediaType.of(mediaTypeStr);
            }
            InputStream in = new BufferedInputStream(new FileInputStream(file));
            return addPart(name, in, fileName, mediaType);
        }

        public Builder addPart(String name, File file) throws IOException {
            return addPart(name, file.toPath());
        }

        public Builder addPart(String name, byte[] bytes) {
            InputStream in = new ByteArrayInputStream(bytes);
            return addPart(name, in);
        }

        public Builder addPart(String name, String content) {
            InputStream in = new ByteArrayInputStream(content.getBytes());
            return addPart(name, in);
        }

        public MultipartBody build() {
            return MultipartBody.this;
        }
    }

    public static Builder builder() {
        return new MultipartBody().new Builder();
    }
}